﻿using System;
using FNN.Networks;
using System.Collections.Generic;

namespace FNN.NetworkMasters
{
    public abstract class NetworkMaster
    {
        /// <summary>
        ///     Делегат для события смены итерации
        /// </summary>
        /// <param name="iterationNumber">Номер итерации</param>
        public delegate void IterationChangedContainer(int iterationNumber);

        /// <summary>
        ///     Делегат для события улучшения результата
        /// </summary>
        /// <param name="iterationNumber">Номер итерации</param>
        /// <param name="iterationResult">Результат итерации</param>
        public delegate void IterationResultsImprovedContainer(int iterationNumber, double iterationResult);

        /// <summary>
        ///     Делегат для события улучшения результата с количеством совершенных операций
        /// </summary>
        /// <param name="iterationResult">Результат итерации</param>
        /// <param name="operationCount">Количество операций</param>
        public delegate void IterationResultsImprovedWithOperationCount(double iterationResult, int operationCount);        

        protected readonly Random Randomizer = new Random();
        protected int IterationsLimitValue;
        protected int PopulationCountValue;
        protected int TimeLimitValue;

        protected int GeneticTimeLimitValue;
        protected int GeneticIterationsLimitValue;

        /// <summary>
        ///     Глобальное ограничение по времени при культивации сети
        /// </summary>
        public int GeneticTimeLimit
        {
            get { return GeneticTimeLimitValue; }
            set { GeneticTimeLimitValue = value; }
        }

        /// <summary>
        ///     Глобальное ограничение по количеству эпох при культивации сети
        /// </summary>
        public int GeneticIterationsLimit
        {
            get { return GeneticIterationsLimitValue; }
            set { GeneticIterationsLimitValue = value; }
        }

        /// <summary>
        ///     Ограничение по времени
        /// </summary>
        public int TimeLimit
        {
            get { return TimeLimitValue; }
            set { TimeLimitValue = value; }
        }

        /// <summary>
        ///     Ограничение по эпохам
        /// </summary>
        public int IterationsLimit
        {
            get { return IterationsLimitValue; }
            set { IterationsLimitValue = value; }
        }

        /// <summary>
        ///     Численность популяции
        /// </summary>
        public int PopulationCount
        {
            get { return PopulationCountValue; }
            set { PopulationCountValue = value; }
        }

        /// <summary>
        ///     Проход эпохи обучения для сети
        /// </summary>
        /// <param name="target">Целевая сеть</param>
        /// <param name="isMultiNetwork">Множественность выходов сети</param>
        public abstract void RunEpoch(ref Network target, bool isMultiNetwork);

        /// <summary>
        ///     Обучить сеть
        /// </summary>
        /// <param name="target">Целевая сеть</param>
        /// <returns></returns>
        public abstract Network TrainNetwork(Network target);

        /// <summary>
        ///     Обучить сеть с множественными выходами
        /// </summary>
        /// <param name="target">Целевая сеть</param>
        /// <returns></returns>
        public abstract Network TrainMultiNetwork(Network target);

        /// <summary>
        ///     Культивирование сети с использованием генетического алгоритма (изменение топологии)
        /// </summary>
        /// <param name="progenitor">Предок</param>
        /// <returns></returns>
        public abstract Network NetworkCultivation(Network progenitor, bool isMultiNetwork);

        /// <summary>
        ///     Культивирование сети с использованием генетического алгоритма (подбор весов)
        /// </summary>
        /// <param name="progenitor">Предок</param>
        /// <param name="isMultiNetwork">Множественность выходов сети</param>
        /// <returns></returns>
        public abstract Network GeneticTrainingEpoch(Network progenitor, bool isMultiNetwork);

        /// <summary>
        ///     Проход эпохи культивирования сети с нужной топологией
        /// </summary>
        /// <param name="targetGeneration">Текущее поколение</param>
        /// <param name="isMultiNetwork">Множественность выходов сети</param>
        /// <returns></returns>
        public abstract List<Network> NetworkCultivationEpoch(List<Network> targetGeneration, bool isMultiNetwork);

        /// <summary>
        ///     Обучение сети с помощью генетического алгоритма
        /// </summary>
        /// <param name="target">Предок</param>
        /// <param name="isMultiNetwork">Множественность выходов сети</param>
        /// <returns>Обученная сеть</returns>
        public abstract Network GeneticNetworkTraining(Network target, bool isMultiNetwork);

        /// <summary>
        ///     Генерация поколения на основе предка
        /// </summary>
        /// <param name="progenitor">Предок</param>
        /// <param name="neededPopulationCount">Необходимая численность</param>
        /// <returns>Новое поколение</returns>
        public abstract List<Network> CreateGeneration(Network progenitor, int neededPopulationCount);

        /// <summary>
        ///     Генерация поколения на основе предыдущего
        /// </summary>
        /// <param name="progenitorGeneration">Предыдущее поколение</param>
        /// <param name="populationMultiplier">Коэффициент увеличения популяции</param>
        /// <returns>Искомое поколение</returns>
        public abstract List<Network> CreateGeneration(List<Network> progenitorGeneration, int populationMultiplier);
    }
}